/****************************************************************************
 * libwiigui
 *
 * gui_gameGrid.cpp
 *
 * GUI class definitions
 ***************************************************************************/

#include "gui.h"
#include "../wpad.h"

#include <unistd.h>
#include "gui_gamegrid.h"
#include "gui_image_async.h"
#include "../settings/cfg.h"
#include "../prompts/PromptWindows.h"
#include "../language/gettext.h"
#include "../menu.h"
#include "fatmounter.h"

#include <string.h>
#include <math.h>
#include <sstream>

//#define SCALE		0.8f
//#define DEG_OFFSET	7
#define RADIUS		780
//#define IN_SPEED	175
//#define SHIFT_SPEED	100
//#define SPEED_STEP	4
//#define SAFETY		320
#define goSteps		10
#include "../main.h"




extern const int vol;

static int Skew1[7][8] =	{
							{-14,-66,14,-34,14,34,-14,66},
							{-10,-44,10,-26,10,26,-10,44},
							{-6,-22,6,-14,6,14,-6,22},
							{0,-11,0,-11,0,11,0,11},
							{-6,-14,6,-22,6,22,-6,14},
							{-10,-26,10,-44,10,44,-10,26},
							{-14,-34,14,-66,14,66,-14,34}
						};
static int Pos1[7][2][2] =	{
						// {{16:9 x,y},{ 4:3 x,y}}
							{{-230,74},	{-320,74}},
							{{-70,74},	{-130,74}},
							{{88,74},	{60,74}},
							{{239,74},	{239,74}},
							{{390,74},	{420,74}},
							{{550,74},	{612,74}},
							{{710,74},	{772,74}}
						};
static int Skew2[18][8] =	{
							{-5,-49,5,-27,5,0,-5,0},
							{-5,0,5,0,5,27,-5,49},
							
							{-5,-49,5,-27,5,0,-5,0},
							{-5,0,5,0,5,27,-5,49},
							
							{-4,-22,4,-14,4,0,-4,0},
							{-4,0,4,0,4,14,-4,22},
							
							{0,-9,0,-5,0,0,0,0},
							{0,0,0,0,0,5,0,9},
							
							{0,0,0,0,0,0,0,0},
							{0,0,0,0,0,0,0,0},
							
							{0,-5,0,-9,0,0,0,0},
							{0,0,0,0,0,9,0,5},
							
							{-4,-14,4,-22,4,0,-4,0},
							{-4,0,4,0,4,22,-4,14},
							
							{-5,-27,5,-49,5,0,-5,0},
							{-5,0,5,0,5,49,-5,27},
							
							{-5,-27,5,-49,5,0,-5,0},
							{-5,0,5,0,5,49,-5,27}
						};
static int Pos2[18][2][2] =	{
						// {{16:9 x,y},{ 4:3 x,y}}
							{{-91,50},	{-166,50}},
							{{-91,193},{-166,193}},
							
							{{3,50},	{-54,50}},
							{{3,193},	{-54,193}},
							
							{{97,50},	{58,50}},
							{{97,193},	{58,193}},
							
							{{187,50},	{166,50}},
							{{187,193},	{166,193}},
							
							{{272,50},	{272,50}},
							{{272,193},	{272,193}},
							
							{{358,50},	{378,50}},
							{{358,193},	{378,193}},
							
							{{449,50},	{487,50}},
							{{449,193},	{487,193}},
							
							{{545,50},	{599,50}},
							{{545,193},	{599,193}},
							
							{{641,50},	{700,50}},
							{{641,193},	{700,193}}
						};
static int Skew3[45][8] =	{
							{-38,-110,15,-42,15,65,-38,32},
							{-38,-75,15,-48,15,45,-38,72},
							{-38,-52,15,-70,15,27,-38,100},

							{-38,-110,15,-42,15,65,-38,32},
							{-38,-75,15,-48,15,45,-38,72},
							{-38,-52,15,-70,15,27,-38,100},

							{-38,-70,15,-24,15,40,-38,27},
							{-38,-50,15,-35,15,40,-38,50},
							{-38,-34,15,-47,15,24,-38,58},

							{-27,-55,19,-22,19,30,-27,22},
							{-27,-40,19,-30,19,30,-27,40},
							{-27,-20,19,-30,19,20,-27,50},

							{-19,-28,0,-17,0,15,-19,10},
							{-19,-30,0,-20,0,12,-19,30},
							{-19,-15,0,-20,0,10,-19,24},

							{-10,-20,3,-13,3,14,-10,10},
							{-10,-20,3,-18,3,18,-10,20},
							{-10,-10,3,-10,3,0,-10,10},

							{-10,-15,3,-12,3,13,-10,13},
							{-10,-17,3,-10,3,10,-10,17},
							{-10,-10,3,-15,3,10,-10,10},

							{-10,-10,3,-10,3,14,-10,14},
							{-10,-10,3,-10,3,10,-10,10},//middle
							{-10,-10,3,-10,3,10,-10,10},

							{-14,-10,4,-20,3,10,-14,10},
							{-14,-10,4,-17,3,17,-14,10},
							{-14,-10,4,-10,3,10,-14,10},

							{-10,-13,3,-20,3,14,-10,10},
							{-10,-18,3,-20,3,20,-10,18},
							{-10,-10,3,-10,3,20,-10,5},

							{-19,-17,0,-28,0,10,-19,15},
							{-19,-20,0,-30,0,30,-19,12},
							{-19,-20,0,-15,0,30,-19,10},

							{-27,-22,19,-55,19,22,-27,30},
							{-27,-30,19,-40,19,40,-27,30},
							{-27,-30,19,-20,19,55,-27,20},

							{-38,-24,15,-70,15,27,-38,40},
							{-38,-35,15,-50,15,50,-38,40},
							{-38,-47,15,-34,15,58,-38,24},

							{-38,-42,15,-110,15,32,-38,60},
							{-38,-48,15,-75,15,70,-38,45},
							{-38,-70,15,-52,15,100,-38,27},

							{-38,-42,15,-110,15,32,-38,60},
							{-38,-48,15,-75,15,70,-38,45},
							{-38,-70,15,-52,15,100,-38,27}
						};
static int Pos3[45][2][2] =	{
						// {{16:9 x,y},{ 4:3 x,y}}
							{{-42,49},	{-91,49}},
							{{-42,153},{-91,153}},
							{{-42,261},{-91,261}},
							
							{{13,58},	{-29,58}},
							{{13,153},	{-29,153}},
							{{13,250},	{-29,250}},
							
							{{68,67},	{33,67}},
							{{68,153},	{33,153}},
							{{68,239},	{33,239}},
							
							{{120,74},	{92,74}},
							{{120,153},	{92,153}},
							{{120,232},	{92,232}},
							
							{{170,78},	{149,78}},
							{{170,153},	{149,153}},
							{{170,228},	{149,228}},
							
							{{214,80},	{200,80}},
							{{214,153},	{200,153}},
							{{214,226},	{200,226}},
							
							{{258,81},	{251,81}},
							{{258,153},	{251,153}},
							{{258,224},	{251,224}},
							
							{{302,81},	{302,81}},
							{{302,153},	{302,153}},
							{{302,223},	{302,223}},
							
							{{346,81},	{353,81}},
							{{346,153},	{353,153}},
							{{346,223},	{353,223}},
							
							{{390,80},	{404,80}},
							{{390,153},	{404,153}},
							{{390,225},	{404,225}},
							
							{{434,77},	{457,77}},
							{{434,153},	{457,153}},
							{{434,227},	{457,227}},
							
							{{484,73},	{512,73}},
							{{484,153},	{512,153}},
							{{484,231},	{512,231}},
							
							{{537,67},	{572,67}},
							{{537,153},	{572,153}},
							{{537,239},	{572,239}},
							
							{{591,58},	{633,58}},
							{{591,153},	{633,153}},
							{{591,250},	{633,250}},
							
							{{660,58},	{660,58}},
							{{660,153},	{660,153}},
							{{660,250},	{660,250}}
			
						};
#define VALUE4ROWS(rows, val1, val2, val3)	(rows==3 ? val3 : (rows==2 ? val2 : val1))
#define ROWS2PAGESIZE(rows)	(rows==3 ? 45 : (rows==2 ? 18 : 7))
static inline int OFFSETLIMIT(int Offset, int rows, int gameCnt)
{
	gameCnt += ( rows - ( gameCnt % rows ) ) % rows; // add count of skiped Entries at end if List
	while(Offset > gameCnt)	Offset -= gameCnt;
	while(Offset < 0) 		Offset += gameCnt;
	return Offset;
} 

// Help-Function to Calc GameIndex
static int GetGameIndex(int pageEntry, int rows, int listOffset, int gameCnt)
{
	int skip = ( rows - ( gameCnt % rows ) ) % rows;					// count of skiped Entries at end if List
	int pagesize = ROWS2PAGESIZE(rows);

	if( gameCnt < (pagesize-2*rows) )
	{
		int listStart = (pagesize-gameCnt)>>1;							// align list on the center
		listStart = listStart - (listStart%rows);						// align listStart to the top row
		if(pageEntry < listStart || pageEntry >= listStart + gameCnt)
			return -1;
		return pageEntry - listStart;
	}
	else
	{
		listOffset = listOffset - (listOffset%rows);					// align listOffset to the top row
		listOffset = listOffset - 2*rows; 								// align listOffset to the left full visible column
		if(listOffset < 0)
			listOffset += gameCnt + skip;								// set the correct Offset
		pageEntry = (listOffset + pageEntry) % (gameCnt + skip);		// get offset of pageEntry
		if(pageEntry >= gameCnt)
			return -1;
		return pageEntry;
	}
}
static GuiImageData *GameGridLoadCoverImage(void * Arg)
{
	return LoadCoverImage((struct discHdr *)Arg, false, false);
}
/**
 * Constructor for the GuiGamegrid class.
 */
GuiGameGrid::GuiGameGrid(int w, int h, struct discHdr * l, int count, const char *themePath, const u8 *imagebg, int selected, int offset) :
noCover(nocoverFlat_png)
{
	width = w;
	height = h;
//	gameCnt = count;			will be set later in Reload
//	gameList = l;				will be set later in Reload
//	listOffset = 0;				will be set later in Reload
//	goLeft = 0;					will be set later in Reload
//	goRight = 0;				will be set later in Reload

	selectable = true;
	focus = 1;					 // allow focus
//	selectedItem = -1;			will be set later in Reload
//	clickedItem = -1;			will be set later in Reload
/*			will be set later in Reload
	rows = Settings.gridRows;
	if ((count<45)&&(rows==3))rows=2;
	if ((count<18)&&(rows==2))rows=1;

	pagesize = ROWS2PAGESIZE(rows);
*/
	trigA = new GuiTrigger;
	trigA->SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A);
	trigL = new GuiTrigger;
	trigL->SetButtonOnlyTrigger(-1, WPAD_BUTTON_LEFT | WPAD_CLASSIC_BUTTON_LEFT, PAD_BUTTON_LEFT);
	trigR = new GuiTrigger;
	trigR->SetButtonOnlyTrigger(-1, WPAD_BUTTON_RIGHT | WPAD_CLASSIC_BUTTON_RIGHT, PAD_BUTTON_RIGHT);
	trig1 = new GuiTrigger;
	trig1->SetButtonOnlyTrigger(-1, WPAD_BUTTON_UP | WPAD_CLASSIC_BUTTON_X, PAD_BUTTON_X);
	trig2 = new GuiTrigger;
	trig2->SetButtonOnlyTrigger(-1, WPAD_BUTTON_DOWN | WPAD_CLASSIC_BUTTON_Y, PAD_BUTTON_Y);
	trigPlus = new GuiTrigger;
	trigPlus->SetButtonOnlyTrigger(-1, WPAD_BUTTON_PLUS | WPAD_CLASSIC_BUTTON_PLUS, 0);
	trigMinus = new GuiTrigger;
	trigMinus->SetButtonOnlyTrigger(-1, WPAD_BUTTON_MINUS | WPAD_CLASSIC_BUTTON_MINUS, 0);

	btnSoundClick = new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume);
	btnSoundOver = new GuiSound(button_over_pcm, button_over_pcm_size, Settings.sfxvolume);

	int btnHeight = (int) lround(sqrt(RADIUS*RADIUS - 90000)-RADIUS-50);

	// Button Left
	btnLeft = new GuiButton(0,0);
	btnLeft->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
	btnLeft->SetPosition(20, btnHeight);
	btnLeft->SetParent(this);
	btnLeft->SetSoundOver(btnSoundOver);
	btnLeft->SetTrigger(trigL);
	btnLeft->SetTrigger(trigMinus);

	// Button Right
	btnRight = new GuiButton(0,0);
	btnRight->SetParent(this);
	btnRight->SetAlignment(ALIGN_RIGHT, ALIGN_MIDDLE);
	btnRight->SetPosition(-20, btnHeight);
	btnRight->SetSoundOver(btnSoundOver);
	btnRight->SetTrigger(trigR);
	btnRight->SetTrigger(trigPlus);

	// Button RowUp
	btnRowUp = new GuiButton(0,0);
	btnRowUp->SetParent(this);
	btnRowUp->SetAlignment(ALIGN_LEFT, ALIGN_TOP);
	btnRowUp->SetPosition(0,0);
	btnRowUp->SetTrigger(trig2);

	// Button RowDown
	btnRowDown = new GuiButton(0,0);
	btnRowDown->SetParent(this);
	btnRowDown->SetAlignment(ALIGN_LEFT, ALIGN_TOP);
	btnRowDown->SetPosition(0,0);
	btnRowDown->SetTrigger(trig1);

	// Page-Stuff
	gameIndex	= NULL;
	titleTT		= NULL;
//	cover		= NULL;
	coverImg	= NULL;
	game		= NULL;

	Reload(l, count, Settings.gridRows, 0);
}


/**
 * Destructor for the GuiGameGrid class.
 */
GuiGameGrid::~GuiGameGrid()
{

	delete btnRight;
	delete btnLeft;
	delete btnRowUp;
	delete btnRowDown;

	delete trigA;
	delete trigL;
	delete trigR;
	delete trigPlus;
	delete trigMinus;
	delete trig1;
	delete trig2;
	delete btnSoundClick;
	delete btnSoundOver;

	for(int i=pagesize-1; i>=0; i--)
	{
		delete game[i];
		delete coverImg[i];
		delete titleTT[i];
	}

	delete [] gameIndex;
	delete [] game;
	delete [] coverImg;
	delete [] titleTT;
}


void GuiGameGrid::SetFocus(int f)
{
	LOCK(this);
	if(!gameCnt)
		return;

	focus = f;

	for(int i=0; i<pagesize; i++)
		game[i]->ResetState();

	if(f == 1 && selectedItem >= 0)
		game[selectedItem]->SetState(STATE_SELECTED);
}


void GuiGameGrid::ResetState()
{
	LOCK(this);
	if(state != STATE_DISABLED)
	{
		state = STATE_DEFAULT;
		stateChan = -1;
	}

	for(int i=0; i<pagesize; i++) {
		game[i]->ResetState();
	}
}


int GuiGameGrid::GetOffset()
{
	LOCK(this);
	return listOffset;
}


int GuiGameGrid::GetClickedOption()
{
	LOCK(this);
	int found = -1;
	if (clickedItem>=0)
	{
		game[clickedItem]->SetState(STATE_SELECTED);
		found = gameIndex[clickedItem];
		clickedItem=-1;
	}
	return found;
}


int GuiGameGrid::GetSelectedOption()
{
	LOCK(this);
	int found = -1;
	for(int i=0; i<pagesize; i++)
	{
		if(game[i]->GetState() == STATE_SELECTED)
		{
			game[i]->SetState(STATE_SELECTED);
			found = gameIndex[i];
			break;
		}
	}
	return found;
}

/**
 * Draw the button on screen
 */
void GuiGameGrid::Draw()
{
	LOCK(this);
	if(!this->IsVisible() || !gameCnt)
		return;

	if(goLeft>0)
	{
		goLeft--;
		int wsi = CFG.widescreen ? 0:1;
		float f2 = ((float)goLeft)/goSteps;
		float f1 = 1.0-f2;
		int (*Pos)[2][2]	= VALUE4ROWS(rows, Pos1, Pos2, Pos3);
		int (*Skew)[8]		= VALUE4ROWS(rows, Skew1, Skew2, Skew3);

		for(int i=0; i<pagesize-rows; i++)
		{
			game[i]->SetPosition(	Pos[i][wsi][0]*f1 + Pos[i+rows][wsi][0]*f2+THEME.gamegrid_x,
									Pos[i][wsi][1]*f1 + Pos[i+rows][wsi][1]*f2+THEME.gamegrid_y);
			
			game[i]->SetSkew(		Skew[i][0]*f1 + Skew[i+rows][0]*f2,
									Skew[i][1]*f1 + Skew[i+rows][1]*f2,
									Skew[i][2]*f1 + Skew[i+rows][2]*f2,
									Skew[i][3]*f1 + Skew[i+rows][3]*f2,
									Skew[i][4]*f1 + Skew[i+rows][4]*f2,
									Skew[i][5]*f1 + Skew[i+rows][5]*f2,
									Skew[i][6]*f1 + Skew[i+rows][6]*f2,
									Skew[i][7]*f1 + Skew[i+rows][7]*f2);
		}
	}
	else if(goRight>0)
	{
		goRight--;
		int wsi = CFG.widescreen ? 0:1;
		float f2 = ((float)goRight)/goSteps;
		float f1 = 1.0-f2;
		int (*Pos)[2][2]	= VALUE4ROWS(rows, Pos1, Pos2, Pos3);
		int (*Skew)[8]		= VALUE4ROWS(rows, Skew1, Skew2, Skew3);
		for(int i=rows; i<pagesize; i++)
		{
			game[i]->SetPosition(	Pos[i][wsi][0]*f1 + Pos[i-rows][wsi][0]*f2+THEME.gamegrid_x,
									Pos[i][wsi][1]*f1 + Pos[i-rows][wsi][1]*f2+THEME.gamegrid_y);
			
			game[i]->SetSkew(		Skew[i][0]*f1 + Skew[i-rows][0]*f2,
									Skew[i][1]*f1 + Skew[i-rows][1]*f2,
									Skew[i][2]*f1 + Skew[i-rows][2]*f2,
									Skew[i][3]*f1 + Skew[i-rows][3]*f2,
									Skew[i][4]*f1 + Skew[i-rows][4]*f2,
									Skew[i][5]*f1 + Skew[i-rows][5]*f2,
									Skew[i][6]*f1 + Skew[i-rows][6]*f2,
									Skew[i][7]*f1 + Skew[i-rows][7]*f2);
		}
	}

	for(int i=0; i<pagesize; i++)
		game[i]->Draw();
	if(gameCnt > pagesize-2*rows)
	{
		btnRight->Draw();
		btnLeft->Draw();
	}

	btnRowUp->Draw();
	btnRowDown->Draw();

	if (focus && Settings.tooltips == TooltipsOn)
		for(int i=0; i<pagesize; i++)
			game[i]->DrawTooltip();

	this->UpdateEffects();
}



/**
 * Change the number of rows
 */
void GuiGameGrid::ChangeRows(int n)
{
	LOCK(this);
	if(n != rows)
		Reload(gameList, gameCnt, n, -1);
}


void GuiGameGrid::Update(GuiTrigger * t)
{
	LOCK(this);
	if(state == STATE_DISABLED || !t || !gameCnt)
		return;

	if(!(game[0]->GetEffect() || game[0]->GetEffectOnOver()))
	{
		for(int i=0; i<pagesize; i++)
			game[i]->SetEffectGrow();
	}
	
	btnRight->Update(t);
	btnLeft->Update(t);
	btnRowUp->Update(t);
	btnRowDown->Update(t);
	
	selectedItem = -1;
	clickedItem = -1;
	for(int i=0; i<pagesize; i++)
	{
		game[i]->Update(t);
		if(game[i]->GetState() == STATE_SELECTED)
		{
			selectedItem = i;
		}
		if(game[i]->GetState() == STATE_CLICKED)
		{
			clickedItem = i;
		}

	}
	// navigation
	if(focus && gameCnt >= (pagesize-2*rows) && goLeft==0 && goRight==0)
	{
		// Left/Right Navigation

		if (btnLeft->GetState() == STATE_CLICKED)
		{
			WPAD_ScanPads();
			u16 buttons = 0;
			for(int i=0; i<4; i++)
				buttons |= WPAD_ButtonsHeld(i);
			if(!((buttons & WPAD_BUTTON_A) || (buttons & WPAD_BUTTON_MINUS) || t->Left()))
			{
				btnLeft->ResetState();
				return;
			}

			if (Settings.xflip==sysmenu || Settings.xflip==yes || Settings.xflip==disk3d)
				goRight	= goSteps;
			else
				goLeft	= goSteps;
		}
		else if(btnRight->GetState() == STATE_CLICKED)
		{
			WPAD_ScanPads();
			u16 buttons = 0;
			for(int i=0; i<4; i++)
				buttons |= WPAD_ButtonsHeld(i);
			if(!((buttons & WPAD_BUTTON_A) || (buttons & WPAD_BUTTON_PLUS) || t->Right()))
			{
				btnRight->ResetState();
				return;
			}
			if (Settings.xflip==sysmenu ||Settings.xflip==yes || Settings.xflip==disk3d)
				goLeft	= goSteps;
			else
				goRight	= goSteps;
		}

		if (goLeft == goSteps)
		{
			GuiButton *tmpButton[rows];
			GuiTooltip *tmpTooltip[rows];
			listOffset = OFFSETLIMIT(listOffset + rows, rows, gameCnt); // set the new listOffset
			// Save left Tooltip & Button and destroy left Image + Image-Data 
			for (int i=0; i<rows; i++)
			{
				delete coverImg[i]; coverImg[i] = NULL;game[i]->SetImage(NULL);
				tmpTooltip[i]	= titleTT[i];
				tmpButton[i]	= game[i];
			}
			// Move all Page-Entries one step left
			for (int i=0; i<(pagesize-rows); i++)
			{
				titleTT[i]		= titleTT[i+rows];
				coverImg[i]		= coverImg[i+rows];
				game[i]			= game[i+rows];
				gameIndex[i]	= gameIndex[i+rows];
			}
			// set saved Tooltip, Button & gameIndex to right
			int wsi = CFG.widescreen ? 0:1;
			int (*Pos)[2][2]	= VALUE4ROWS(rows, Pos1, Pos2, Pos3);
			int (*Skew)[8]		= VALUE4ROWS(rows, Skew1, Skew2, Skew3);

			for (int i=0; i<rows; i++)
			{
				int ii = i+pagesize-rows;
				gameIndex[ii]		= GetGameIndex(ii, rows, listOffset, gameCnt);
				titleTT[ii]			= tmpTooltip[i];
				coverImg[ii]		= NULL;
				if(gameIndex[ii] != -1)
				{
					coverImg[ii]	= new GuiImageAsync(GameGridLoadCoverImage, &gameList[gameIndex[ii]], sizeof(struct discHdr), &noCover);
					if(coverImg[ii])
					{
						coverImg[ii]		->SetWidescreen(CFG.widescreen);
						coverImg[ii]		->SetScale(VALUE4ROWS(rows, 1.0, 0.6, 0.26));
						coverImg[ii]		->SetPosition(0,VALUE4ROWS(rows, 0, -50, -80));
					}
					titleTT[ii]		->SetText(get_title(&gameList[gameIndex[ii]]));
				}
				else
				{
					titleTT[ii]		->SetText(NULL);
				}

				game[ii]			= tmpButton[i];
				game[ii]			->SetImage(coverImg[ii]);
				game[ii]			->SetPosition(Pos[ii][wsi][0], Pos[ii][wsi][1]);
				game[ii]			->SetSkew(&Skew[ii][0]);
				game[ii]			->RemoveToolTip();
				if(gameIndex[ii] != -1)
				{
					game[ii]		->SetClickable(true);
					game[ii]		->SetVisible(true);
				}
				else
				{
					game[ii]		->SetVisible(false);
					game[ii]		->SetClickable(false);
					game[ii]		->RemoveSoundOver();
				}
			}
			// Set Tooltip-Position
			int ttoffset_x = CFG.widescreen ? VALUE4ROWS(rows, 70, 35, 0) : VALUE4ROWS(rows, 150, 55, 25);
			int ttoffset_y = -VALUE4ROWS(rows, 224, 133, 68)/4;
			for (int i=0; i<pagesize; i++)
			{
				switch((i*3)/pagesize)
				{
					case 0:
						game[i]->SetToolTip(titleTT[i], ttoffset_x, ttoffset_y, ALIGN_LEFT, ALIGN_MIDDLE);
						break;
					case 1:
						game[i]->SetToolTip(titleTT[i], 0, ttoffset_y, ALIGN_CENTRE, ALIGN_MIDDLE);
						break;
					case 2:
						game[i]->SetToolTip(titleTT[i], -ttoffset_x, ttoffset_y, ALIGN_RIGHT, ALIGN_MIDDLE);
						break;
					default:
						break;
				}		
			}
		}
		else if (goRight == goSteps)
		{
			GuiButton *tmpButton[rows];
			GuiTooltip *tmpTooltip[rows];
			listOffset = OFFSETLIMIT(listOffset - rows, rows, gameCnt); // set the new listOffset
			// Save right Button & Tooltip and destroy right Image-Data 
			for (int i=0; i<rows; i++)
			{
				int ii = i+pagesize-rows;
				delete coverImg[ii]; coverImg[ii] = NULL; game[ii]->SetImage(NULL);
				tmpTooltip[i]	= titleTT[ii];
				tmpButton[i]	= game[ii];
			}
			// Move all Page-Entries one step right
			for (int i=pagesize-1; i>=rows; i--)
			{
				titleTT[i]		= titleTT[i-rows];
				coverImg[i]		= coverImg[i-rows];
				game[i]			= game[i-rows];
				gameIndex[i]	= gameIndex[i-rows];
			}
			// set saved Image, Button & gameIndex to left
			int wsi = CFG.widescreen ? 0:1;
			int (*Pos)[2][2]	= VALUE4ROWS(rows, Pos1, Pos2, Pos3);
			int (*Skew)[8]		= VALUE4ROWS(rows, Skew1, Skew2, Skew3);

			for (int i=0; i<rows; i++)
			{
				gameIndex[i]		= GetGameIndex(i, rows, listOffset, gameCnt);
				titleTT[i]			= tmpTooltip[i];
				coverImg[i]			= NULL;
				if(gameIndex[i] != -1)
				{
					coverImg[i]	= new GuiImageAsync(GameGridLoadCoverImage, &gameList[gameIndex[i]], sizeof(struct discHdr), &noCover);
					if(coverImg[i])
					{
						coverImg[i]		->SetWidescreen(CFG.widescreen);
						coverImg[i]		->SetScale(VALUE4ROWS(rows, 1.0, 0.6, 0.26));
						coverImg[i]		->SetPosition(0,VALUE4ROWS(rows, 0, -50, -80));
					}
					titleTT[i]		->SetText(get_title(&gameList[gameIndex[i]]));
				}
				else
				{
					titleTT[i]		->SetText(NULL);
				}
				game[i]				= tmpButton[i];
				game[i]				->SetImage(coverImg[i]);
				game[i]				->SetPosition(Pos[i][wsi][0], Pos[i][wsi][1]);
				game[i]				->SetSkew(&Skew[i][0]);
				game[i]				->RemoveToolTip();
				if(gameIndex[i] != -1)
				{
					game[i]			->SetClickable(true);
					game[i]			->SetVisible(true);
				}
				else
				{
					game[i]			->SetVisible(false);
					game[i]			->SetClickable(false);
					game[i]			->RemoveSoundOver();
				}
			}
			// Set Tooltip-Position
			int ttoffset_x = CFG.widescreen ? VALUE4ROWS(rows, 70, 35, 0) : VALUE4ROWS(rows, 150, 55, 25);
			int ttoffset_y = -VALUE4ROWS(rows, 224, 133, 68)/4;
			for (int i=0; i< pagesize; i++)
			{
				switch((i*3)/pagesize)
				{
					case 0:
						game[i]->SetToolTip(titleTT[i], ttoffset_x, ttoffset_y, ALIGN_LEFT, ALIGN_MIDDLE);
						break;
					case 1:
						game[i]->SetToolTip(titleTT[i], 0, ttoffset_y, ALIGN_CENTRE, ALIGN_MIDDLE);
						break;
					case 2:
						game[i]->SetToolTip(titleTT[i], -ttoffset_x, ttoffset_y, ALIGN_RIGHT, ALIGN_MIDDLE);
						break;
					default:
						break;
				}		
			}
		}
	}

	if ((btnRowUp->GetState() == STATE_CLICKED))
	{
		if ((rows==1)&&(gameCnt>=18))this->ChangeRows(2);
		else if ((rows==2)&&(gameCnt>=45))this->ChangeRows(3);
		btnRowUp->ResetState();
		return;
	}

	if ((btnRowDown->GetState() == STATE_CLICKED))
	{
		if (rows==3)this->ChangeRows(2);
		else if (rows==2)this->ChangeRows(1);
		btnRowDown->ResetState();
		return;
	}

	if(updateCB)
		updateCB(this);
}


void GuiGameGrid::Reload(struct discHdr * l, int count, int Rows, int ListOffset)
{
	LOCK(this);
	
	// CleanUp
	if(game)
		for(int i=pagesize-1; i>=0; i--)
			delete game[i];

	if(coverImg)
		for(int i=pagesize-1; i>=0; i--)
			delete coverImg[i];

//	if(cover)
//		for(int i=pagesize-1; i>=0; i--)
//			delete cover[i];
	
	if(titleTT)
		for(int i=pagesize-1; i>=0; i--)
			delete titleTT[i];

	delete [] gameIndex;
	delete [] game;
	delete [] coverImg;
//	delete [] cover;
	delete [] titleTT;
	
	gameList = l;
	gameCnt = count;
	goLeft = 0;
	goRight = 0;

	rows = Rows > 3 ? 3 : (Rows < 1 ? 1 : Rows);
	if ((count<45)&&(rows==3))rows=2;
	if ((count<18)&&(rows==2))rows=1;

	if(ListOffset>=0) // if ListOffset < 0 then no change
		listOffset = ListOffset;
	listOffset = OFFSETLIMIT(listOffset, rows, gameCnt);

	selectedItem = -1;
	clickedItem = -1;

	pagesize = ROWS2PAGESIZE(rows);

	// Page-Stuff
	gameIndex	= new int[pagesize];
	titleTT		= new GuiTooltip *[pagesize];
//	cover		= new GuiImageData *[pagesize];
	coverImg	= new GuiImageAsync *[pagesize];
	game		= new GuiButton *[pagesize];


	int wsi = CFG.widescreen ? 0:1;
	int (*Pos)[2][2]	= VALUE4ROWS(rows, Pos1, Pos2, Pos3);
	int (*Skew)[8]		= VALUE4ROWS(rows, Skew1, Skew2, Skew3);

	int ttoffset_x = CFG.widescreen ? VALUE4ROWS(rows, 70, 35, 0) : VALUE4ROWS(rows, 150, 55, 25);
	int ttoffset_y = -VALUE4ROWS(rows, 224, 133, 68)/4;
		
	for(int i=0; i < pagesize; i++)
	{
		//------------------------
		// Index
		//------------------------
		gameIndex[i] = GetGameIndex(i, rows, listOffset, gameCnt);

		//------------------------
		// Tooltip
		//------------------------
		if( gameIndex[i] != -1 ) 
			titleTT[i] = new GuiTooltip(get_title(&gameList[gameIndex[i]]), THEME.tooltipAlpha);
		else
			titleTT[i] = new GuiTooltip(NULL, THEME.tooltipAlpha);

		//------------------------
		// ImageData
		//------------------------
//		if( gameIndex[i] != -1 ) 
//			cover[i] = LoadCoverImage(&gameList[gameIndex[i]], false /*bool Prefere3D*/);
//		else
//			cover[i] = new GuiImageData(NULL);

		//------------------------
		// Image
		//------------------------
		coverImg[i] = NULL;
		if( gameIndex[i] != -1 )
		{ 
			coverImg[i]	= new GuiImageAsync(GameGridLoadCoverImage, &gameList[gameIndex[i]], sizeof(struct discHdr), &noCover);
			if(coverImg[i])
			{
				coverImg[i]->SetWidescreen(CFG.widescreen);
		//		if ( rows == 2 )		coverImg[i]->SetScale(.6);		//these are the numbers for 2 rows
		//		else if ( rows == 3 )	coverImg[i]->SetScale(.26);	//these are the numbers for 3 rows
				coverImg[i]->SetScale(VALUE4ROWS(rows, 1.0, 0.6, 0.26));
				coverImg[i]->SetPosition(0,VALUE4ROWS(rows, 0, -50, -80));
			}
		}
		
		//------------------------
		// GameButton
		//------------------------
		game[i] = new GuiButton(VALUE4ROWS(rows, 160, 75, 35), VALUE4ROWS(rows, 224, 133, 68));
		game[i]->SetParent(this);
		game[i]->SetImage(coverImg[i]);
		game[i]->SetAlignment(ALIGN_TOP,ALIGN_LEFT);
		game[i]->SetPosition(Pos[i][wsi][0]+THEME.gamegrid_x, Pos[i][wsi][1]+THEME.gamegrid_y);
		game[i]->SetSkew(&Skew[i][0]);
		game[i]->SetTrigger(trigA);
		game[i]->SetSoundOver(btnSoundOver);
		game[i]->SetSoundClick(btnSoundClick);
		game[i]->SetRumble(false);
		switch((i*3)/pagesize)
		{
			case 0:
				game[i]->SetToolTip(titleTT[i], ttoffset_x, ttoffset_y, ALIGN_LEFT, ALIGN_MIDDLE);
				break;
			case 1:
				game[i]->SetToolTip(titleTT[i], 0, ttoffset_y, ALIGN_CENTRE, ALIGN_MIDDLE);
				break;
			case 2:
				game[i]->SetToolTip(titleTT[i], -ttoffset_x, ttoffset_y, ALIGN_RIGHT, ALIGN_MIDDLE);
				break;
			default:
				break;
		}		
		if(gameIndex[i] >= 0)
		{
			game[i]->SetClickable(true);
			game[i]->SetVisible(true);
		}
		else
		{
			game[i]->SetVisible(false);
			game[i]->SetClickable(false);
	//		game[i]->RemoveSoundOver();
		}
	}
	Settings.gridRows = rows;
	if(isInserted(bootDevice)) 
		cfg_save_global();
}

